// Base error interface
export interface BaseError {
    message: string
    code: string
    timestamp: Date
    cause?: unknown
}

// Error codes enum
export enum ErrorCode {
    // 保留這些被使用的錯誤碼
    VALIDATION_ERROR = "ERR_VALIDATION",
    AUTHENTICATION_ERROR = "ERR_AUTH",
    SERVER_ERROR = "ERR_SERVER",
    NETWORK_ERROR = "ERR_NETWORK",
    BUSINESS_ERROR = "ERR_BUSINESS",
    NOT_FOUND = "ERR_NOT_FOUND",
    REPOSITORY_ERROR = "ERR_REPOSITORY",
    FETCH_ERROR = "ERR_FETCH",
    // 其他可能在將來會用到的關鍵錯誤碼
    CBOR_ERROR = "ERR_CBOR",
    UNKNOWN_ERROR = "ERR_UNKNOWN",
    FILE_UPLOAD_ERROR = "ERR_FILE_UPLOAD",
}

// Base custom error class
export abstract class CustomError extends Error implements BaseError {
    public readonly timestamp: Date

    constructor(
        public readonly message: string,
        public readonly code: ErrorCode,
        public readonly cause?: unknown,
    ) {
        super(message)
        this.name = this.constructor.name
        this.timestamp = new Date()
        Object.setPrototypeOf(this, new.target.prototype)
    }

    public toJSON(): Record<string, unknown> {
        return {
            name: this.name,
            message: this.message,
            code: this.code,
            timestamp: this.timestamp,
            cause: this.cause,
        }
    }

    public toString(): string {
        return `${this.name}: [${this.code}] ${this.message}`
    }
}

// Specific error classes
export class ValidationError extends CustomError {
    constructor(message: string, cause?: unknown) {
        super(message, ErrorCode.VALIDATION_ERROR, cause)
    }
}

export class AuthenticationError extends CustomError {
    constructor(message: string, cause?: unknown) {
        super(message, ErrorCode.AUTHENTICATION_ERROR, cause)
    }
}

export class ServerError extends CustomError {
    constructor(message: string, cause?: unknown) {
        super(message, ErrorCode.SERVER_ERROR, cause)
    }
}

export class NetworkError extends CustomError {
    constructor(message: string, cause?: unknown) {
        super(message, ErrorCode.NETWORK_ERROR, cause)
    }
}

export class BusinessError extends CustomError {
    constructor(message: string, cause?: unknown) {
        super(message, ErrorCode.BUSINESS_ERROR, cause)
    }
}

export class NotFoundError extends CustomError {
    constructor(message: string, cause?: unknown) {
        super(message, ErrorCode.NOT_FOUND, cause)
    }
}

export class RepositoryError extends CustomError {
    constructor(message: string, cause?: unknown) {
        super(message, ErrorCode.REPOSITORY_ERROR, cause)
    }
}

export class FetchError extends CustomError {
    constructor(message: string, cause?: unknown) {
        super(message, ErrorCode.FETCH_ERROR, cause)
    }
}

export class CborError extends CustomError {
    constructor(message: string, cause?: unknown) {
        super(message, ErrorCode.CBOR_ERROR, cause)
    }
}

export class FileUploadError extends CustomError {
    constructor(message: string, cause?: unknown) {
        super(message, ErrorCode.FILE_UPLOAD_ERROR, cause)
    }
}

// Error factory for creating errors
export class ErrorFactory {
    static create(type: ErrorCode, message = "An error occurred", cause?: unknown): CustomError {
        switch (type) {
            case ErrorCode.VALIDATION_ERROR:
                return new ValidationError(message, cause)
            case ErrorCode.AUTHENTICATION_ERROR:
                return new AuthenticationError(message, cause)
            case ErrorCode.SERVER_ERROR:
                return new ServerError(message, cause)
            case ErrorCode.NETWORK_ERROR:
                return new NetworkError(message, cause)
            case ErrorCode.BUSINESS_ERROR:
                return new BusinessError(message, cause)
            case ErrorCode.NOT_FOUND:
                return new NotFoundError(message, cause)
            case ErrorCode.REPOSITORY_ERROR:
                return new RepositoryError(message, cause)
            case ErrorCode.FETCH_ERROR:
                return new FetchError(message, cause)
            default:
                return new ServerError(`Unknown error: ${message}`, cause)
        }
    }
    static createValidationError(message: string, cause?: unknown): CustomError {
        return new ValidationError(message, cause)
    }
    static createAuthenticationError(message: string, cause?: unknown): CustomError {
        return new AuthenticationError(message, cause)
    }
    static createServerError(message: string, cause?: unknown): CustomError {
        return new ServerError(message, cause)
    }
    static createNetworkError(message: string, cause?: unknown): CustomError {
        return new NetworkError(message, cause)
    }
    static createBusinessError(message: string, cause?: unknown): CustomError {
        return new BusinessError(message, cause)
    }
    static createNotFoundError(message: string, cause?: unknown): CustomError {
        return new NotFoundError(message, cause)
    }
    static createRepositoryError(message: string, cause?: unknown): CustomError {
        return new RepositoryError(message, cause)
    }
    static createFetchError(message: string, cause?: unknown): CustomError {
        return new FetchError(message, cause)
    }
    static createUnknownError(message: string, cause?: unknown): CustomError {
        return new ServerError(message, cause)
    }
    static createCborError(message: string, cause?: unknown): CustomError {
        return new CborError(message, cause)
    }
    static createFileUploadError(message: string, cause?: unknown): CustomError {
        return new FileUploadError(message, cause)
    }
}
